/* Copyright (c) 2011 by Mani Brundha Kattamuri, Haritha Subramanyam
 *
 * Project Info:  http://code.google.com/p/andriod-travelapp-csc780/wiki/Design
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 */
package com.example.TravelApp.search.common;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import org.json.JSONException;
import org.json.JSONObject;

import com.example.TravelApp.constants.MapConstants;

import android.os.Parcel;
import android.os.Parcelable;
import android.util.Base64InputStream;
import android.util.Log;

/**
 * This class is modeled to hold a place object. Each PlaceObject represents a
 * JSON object returned from the Google places API. Here we parse the JSON
 * object to retrieve the place details.
 * 
 * @author Haritha Subramanyam, Mani Brundha
 * 
 */

public class PlaceObject implements Comparable<Object>, Parcelable,
		Serializable {

	private static final long serialVersionUID = 7158561086333975907L;
	private String venueName;
	private String addr;
	private String rating = "0";
	private String latitude;
	private String longitude;
	private String url;
	private String iconURLStr;
	private String types;
	private int time = MapConstants.DEFAULTTIME;
	private boolean isVisited = false;
	String[] typesArray;

	/**
	 * Constructs a PlaceOject by parsing the JSON object
	 * 
	 * @param json
	 *            - returned from the google places API
	 * @throws JSONException
	 */
	public PlaceObject(JSONObject json) throws JSONException {
		try {
			venueName = json.getString("name");
			isVisited = false;
			addr = json.getString("vicinity");

			rating = json.getString("rating");
			latitude = json.getJSONObject("geometry").getJSONObject("location")
					.getString("lat");
			longitude = json.getJSONObject("geometry")
					.getJSONObject("location").getString("lng");
			types = json.getJSONArray("types").toString();
			if (types == "" || types == null) {
				time = MapConstants.DEFAULTTIME;
			} else {
				typesArray = types.split(",");
				time = getTimeForTypes(typesArray);
			}
			iconURLStr = json.getString("icon");
		} catch (JSONException e) {
			// JSON exceptions are logged and ignored. Usually found due to null
			// values for rating
			// and other information
			Log.e("log_tag", "Error in parsing JSON" + e.toString());
		}
	}

	/**
	 * Returns the isVisited instance variable of the placeObject
	 * 
	 * @return isVisited
	 */
	public boolean getIsVisited() {
		return isVisited;
	}

	/**
	 * Sets the isVisited instance variable
	 * 
	 * @param flag
	 *            - is visited flag for the place
	 */
	public void setIsVisited(boolean flag) {
		isVisited = flag;
	}

	/**
	 * Returns the VenueName of the placeObject
	 * 
	 * @return VenueName
	 */
	public String getVenueName() {
		return venueName;
	}

	/**
	 * Returns the time instance variable of the placeObject
	 * 
	 * @return time
	 */
	public int getIntrestTime() {
		return time;
	}

	/**
	 * Returns the address of the placeObject
	 * 
	 * @return address
	 */
	public String getAddress() {
		return addr;
	}

	/**
	 * Returns the rating of the placeObject
	 * 
	 * @return rating
	 */
	public String getRating() {
		return rating;
	}

	/**
	 * Returns the latitude instance variable of the placeObject
	 * 
	 * @return latitude
	 */
	public String getLatitude() {
		return latitude;
	}

	/**
	 * Returns the longitude instance variable of the placeObject
	 * 
	 * @return longitude
	 */

	public String getLongitude() {
		return longitude;
	}

	/**
	 * Returns the url instance variable of the placeObject
	 * 
	 * @return url
	 */

	public String getURL() {
		return url;
	}

	/**
	 * Returns the String which contains the url for the icon of the placeObject
	 * 
	 * @return iconURLStr
	 */
	public String getIconURLStr() {

		return iconURLStr;
	}

	/**
	 * Returns the types or keywords associated with the place object as a comma
	 * separated array
	 * 
	 * @return types
	 */
	public String getTypes() {
		return this.types;
	}

	/**
	 * Returns the latitude and longitude associated with the place object
	 * 
	 * @return string with the latitude and longitude separated by comma
	 */
	public String getLatitudeAndLongitude() {
		return this.latitude + "," + this.longitude;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Comparable#compareTo(java.lang.Object) This function is
	 * implemented as part of the comparable interface here we compare two
	 * PlaceObjects with respect to their rating
	 * 
	 * @returns Zero is returned when both values are equal 1 is returned when
	 * values of the received object is greater than the instance variable -1 is
	 * returned when values of the received object is less than the instance
	 * variable
	 */

	public int compareTo(Object object) {
		PlaceObject placeObject = (PlaceObject) object;
		if (Float.parseFloat(this.rating) < Float.parseFloat(placeObject
				.getRating())) {
			return 1;// greater
		} else if (Float.parseFloat(this.rating) > Float.parseFloat(placeObject
				.getRating())) {
			return -1;// less than
		} else {
			return 0;// equals
		}

	}

	/**
	 * Reads the necessary information from the input parcel and assigns them to
	 * the instance variables
	 * 
	 * @param in
	 *            - input parcel
	 */
	private PlaceObject(Parcel in) {
		venueName = in.readString();
		boolean[] myBooleanArr = new boolean[1];
		in.readBooleanArray(myBooleanArr);
		isVisited = myBooleanArr[0];
		addr = in.readString();
		rating = in.readString();
		latitude = in.readString();
		longitude = in.readString();
		types = in.readString();
		iconURLStr = in.readString();
	}

	public static final Parcelable.Creator<PlaceObject> CREATOR = new Parcelable.Creator<PlaceObject>() {

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * android.os.Parcelable.Creator#createFromParcel(android.os.Parcel)
		 */
		@Override
		public PlaceObject createFromParcel(Parcel source) {
			return new PlaceObject(source);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see android.os.Parcelable.Creator#newArray(int)
		 */
		@Override
		public PlaceObject[] newArray(int size) {
			return new PlaceObject[size];
		}

	};

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.os.Parcelable#describeContents()
	 */

	public int describeContents() {
		return 0;
	}

	/*
	 * (non-Javadoc) Writes the values to the destination parcel. The values are
	 * taken from the instance variables of each of the objects. This wrapping
	 * is necessary to pass a list of place objects through intent to other
	 * activities.
	 * 
	 * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int)
	 */
	@Override
	public void writeToParcel(Parcel dest, int flags) {
		// TODO Auto-generated method stub
		dest.writeString(venueName);
		dest.writeBooleanArray(new boolean[] { isVisited });
		dest.writeString(addr);
		dest.writeString(rating);
		dest.writeString(latitude);
		dest.writeString(longitude);
		dest.writeString(types);
		dest.writeString(iconURLStr);

	}

	/**
	 * Returns the whether the time spent in a place would be high, low or
	 * moderate
	 * 
	 * @param typesString
	 * @return low, moderate or high
	 */
	private int getTimeForTypes(String[] typesString) {
		final int high = 6, low = 1, moderate = 3, defaultTime = 3;
		for (int i = 0; i < typesString.length; i++) {
			if (typesString[i].equals("amusement_park")
					|| typesString[i].equals("zoo")
					|| typesString[i].equals("campground")
					|| typesString[i].equals("museum")
					|| typesString[i].equals("natural_feature")
					|| typesString[i].equals("point_of_interest"))
				return MapConstants.HIGH;
			else if (typesString[i].equals("park")
					|| typesString[i].equals("aquarium")
					|| typesString[i].equals("art_gallery")
					|| typesString[i].equals("bowling_alley")
					|| typesString[i].equals("casino")
					|| typesString[i].equals("jewelry_store")
					|| typesString[i].equals("spa")
					|| typesString[i].equals("stadium")
					|| typesString[i].equals("place_of_worship"))
				return MapConstants.MODERATE;
			else if (typesString[i].equals("shopping_mall")
					|| typesString[i].equals("clothing_store")
					|| typesString[i].equals("convenience_store")
					|| typesString[i].equals("shoe_store")
					|| typesString[i].equals("church")
					|| typesString[i].equals("city_hall")
					|| typesString[i].equals("university"))
				return MapConstants.LOW;
		}
		return MapConstants.MODERATE;
	}

	/**
	 * Converts a string to a place object
	 * 
	 * @param encodedObject
	 *            - string to be converted
	 * @return - object - string converted to object
	 */
	public static Object toString(String encodedObject) {
		try {
			return new ObjectInputStream(new Base64InputStream(
					new ByteArrayInputStream(encodedObject.getBytes()), 0))
					.readObject();
		} catch (Exception e) {
			return null;
		}

	}

}